﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VietThinks.Model
{
    public class RepositoryScope : IDisposable
    {
        private RepositoryScope(DomainRepository repository)
        {
            this.repository = repository;
        }

        private readonly DomainRepository repository;

        private static readonly IDictionary<int, Stack<DomainRepository>> repositoryStacks =
            new Dictionary<int, Stack<DomainRepository>>();

        private static readonly object syncLock = new object();

        private static Stack<DomainRepository> ActiveStack
        {
            get
            {
                int stackId = System.Threading.Thread.CurrentThread.ManagedThreadId;

                lock (syncLock)
                {
                    if (!repositoryStacks.ContainsKey(stackId))
                    {
                        repositoryStacks.Add(stackId, new Stack<DomainRepository>());
                    }
                }

                return repositoryStacks[stackId];
            }
        }

        public static DomainRepository ActiveRepository
        {
            get
            {
                var activeStack = RepositoryScope.ActiveStack;

                lock (syncLock)
                {
                    if (activeStack.Count > 0)
                    {
                        return activeStack.Peek();
                    }
                }

                return null;
            }
        }

        private static void SlideInto(DomainRepository repository)
        {
            RepositoryScope.ActiveStack.Push(repository);
        }

        private static void SlideOutOf(DomainRepository repository)
        {
            if (RepositoryScope.ActiveStack.Peek() == repository)
            {
                RepositoryScope.ActiveStack.Pop();
            }
        }

        public static bool IsOutOfScope(DomainRepository repository)
        {
            return !RepositoryScope.ActiveStack.Any(r => r == repository);
        }

        public static RepositoryScope Share(DomainRepository repository)
        {
            var scope = new RepositoryScope(repository);

            SlideInto(repository);

            return scope;
        }

        #region IDisposable Members

        public void Dispose()
        {
            SlideOutOf(this.repository);
        }

        #endregion
    }
}
